#ifndef ENTITY_H_
#define ENTITY_H_

#include <list>

#include "irrlicht.h"

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

class zone;
class PostOffice;
class Message;

/*!
	The Entity class provides the bases of things or characters
	evolving in the world.
	These bases includes:
	- the ability to send and receive messages to/from other Entities or group of Entities
	- a node to the 3D engine's scene graph
	- a type (for potential future use)
*/
class Entity
{
	friend class PostOffice;
	
	private:
	int currentZone__;			/**< Current zone index. -1 if no zones found. Currently not used at all; here only for future optimization. */
	int lastZone__;				/**< Last zone index the entity was. set to -1 if not defined. Currently not used at all; here only for future optimization. */
	std::list<Message> mailbox__;		/**< the mailbox from where to read messages. It is private because sub-classes of Entity should not be able to access it directly. */

	protected:
	irr::core::string<c8> type__;		/**< The string which contains the type (which is unused for now). */
	irr::core::string<c8> group__;		/**< The string which contains the group for messaging system. */

	ISceneNode* node__;			/**< The node to the 3D engine's scene graph. */
	ISceneManager* smgr__;			/**< The 3D engine's scene manager; it is not strictly needed but can be used as a shortcut when coding. */

	public:
	/*! Constructor. It just initialize the scene manager, so, you shouldn't create an instance without the engine initialized. */
	Entity();
	/*! Destructor. It frees the scene node, removing it from the scene graph; but doesn't do anything if the node__ already equals 0. */
	virtual ~Entity();

	/*! Returns the type (not in terms of classes) of the Entity. */
	virtual irr::core::string<c8>& getType();
	/*! Sets the type of the Entity. */
	virtual void setType(const irr::core::string<c8>& type);

	/*! Returns the messaging system's group of the Entity. */
	virtual irr::core::string<c8>& getGroup();
	/*! Register to a group in the messaging system. If already in a group, then unregisters first, so an Entity can not be in two (or more) groups at a time. */
	void setGroup(const irr::core::string<c8>& group);

	/*! Returns the scene node. This method does not call node__->grab(), so you MUST NOT drop the node yourself (unless you grab it first). See details from irr::IReferenceCounted. */
	virtual ISceneNode* getNode();
	/*! Updates the Entity for a frame. This method must be defined in sub-classes. You should check the World class to see how to retrieve the elapsed time since the last frame. */
	virtual void update() = 0;


	/*! Send a message to an Entity (can be yourself). The receiver Entity must be registered in the Map for the message to be successfull delivered (the program should not crash even if the receiver equals 0; it is yet to test). */
	void sendMessage(Entity* receiver, const std::string& message);
	
	/*! Send a message with extradata */
	void sendMessage(Entity* receiver, const std::string& message, const std::string& extra);

	/*! send a message with extradata and location */
	void sendMessage(Entity* receiver, const std::string& message, const std::string& extra, irr::core::vector3df about);
	/*! Send a message to a group of Entities. All entities registered in the messaging system's given group should receive the message. It doesn't matters if the Entities are registered in the Map. */
	void sendMessage(const std::string& group, const std::string& message);

	/*! Send a message with extradata to a group of Entities. */
	void sendMessage(const std::string& group, const std::string& message, const std::string& extra, irr::core::vector3df about);

	/*! Checks the mailbox, and returns true if there is one or more messages. */
	bool checkMail();
	/*! Returns the first message arrived (a la FIFO). If there's no messages in the mailbox, then returns an empty message. It is your responsability to check that. */
	Message readMessage();

	/*! Sets the last zone index the entity was in. Currently not used. */
	void setLastZone(int z);
	/*! Sets the current zone index the entity is in. Currently not used. */
	void setZone(int z);
	/*! Returns the last zone index the entity was in. Currently not used. */
	int getLastZone();
	/*! Gets the current zone index the entity was in. Currently not used. */
	int getZone();

	/*! Used for debugging purposed, it enables or disables the bounding box of the scene node. */
	virtual void showBB(bool enabled);
};

#endif

